#include "itemrow.h"

#include "dummyrow.h"
#include "sourcerow.h"

#include "item.h"
#include "source.h"

#include "quantitydelegate.h"

#include "urlutils.h"

#include <QStandardItem>
#include <QClipboard>
#include <QApplication>

#include <assert.h>

ItemRow::ItemRow(Item *item)
:   QObject()
,   m_item(item)
,   m_dummyRow(NULL)
{
    createItems();
    createDummyRow();

    connect(QApplication::clipboard(), SIGNAL(dataChanged())
        , this, SLOT(clipboard_dataChanged()));

    connect(item, SIGNAL(sourceAdded(Source*))
        , this, SLOT(item_sourceAdded(Source*)));

    connect(item, SIGNAL(sourceRemoved(Source*))
        , this, SLOT(item_sourceRemoved(Source*)));

    fillUp();
}

void ItemRow::createItems()
{
    m_nameItem = new QStandardItem(m_item->name());
    m_nameItem->setEditable(true);
    m_nameItem->setIcon(QIcon(":/item"));

    m_nameItem->setCheckable(true);
    m_nameItem->setCheckState(m_item->ignored() ? Qt::Unchecked : Qt::Checked);

    m_nullItem[0] = new QStandardItem();
    m_nullItem[0]->setEditable(false);

    m_quantityItem = new QStandardItem(
        QuantityDelegate::textFromValue(m_item->quantity()));
    m_quantityItem->setData(Qt::AlignRight, Qt::TextAlignmentRole);
    m_quantityItem->setData(m_item->quantity(), QuantityDelegate::dataRole());
    m_quantityItem->setEditable(true);

    m_nullItem[1] = new QStandardItem();
    m_nullItem[1]->setEditable(false);

    emit multipleColumnWidthsChanged();

    // connect

    connect(m_item, SIGNAL(nameChanged(QString))
        , this, SLOT(item_nameChanged(QString)));

    connect(m_item, SIGNAL(quantityChanged(uint))
        , this, SLOT(item_quantityChanged(uint)));

    connect(m_item, SIGNAL(ignoreStateChanged(bool))
        , this, SLOT(item_ignoreStateChanged(bool)));
}

void ItemRow::createDummyRow()
{
    m_dummyRow = new DummyRow(tr("Append new Source"));
    firstColumnItem()->appendRow(m_dummyRow->items());

    updateDummyRowStatus();
}

ItemRow::~ItemRow()
{
    if(m_dummyRow)
    {
        firstColumnItem()->takeRow(m_dummyRow->row());
        delete m_dummyRow;
    }

    delete m_nameItem;
    delete m_nullItem[0];
    delete m_quantityItem;
    delete m_nullItem[1];
}

void ItemRow::fillUp()
{
    foreach(Source *source, m_item->sources())
        item_sourceAdded(source);
}

QList<QStandardItem*> ItemRow::items() const
{
    return QList<QStandardItem*>()
        << m_nameItem << m_nullItem[0] << m_quantityItem << m_nullItem[1];
}

const int ItemRow::row() const
{
    return firstColumnItem()->row();
}

QStandardItem *ItemRow::firstColumnItem() const
{
    return m_nameItem;
}

Item *ItemRow::item()
{
    return m_item;
}

const bool ItemRow::hasItemInRow(QStandardItem *item) const
{
    return items().contains(item);
}

void ItemRow::itemChanged(QStandardItem *item)
{
    if(item == m_nameItem)
    {
        if(item->checkState() == (m_item->ignored() ? Qt::Unchecked : Qt::Checked))
            name_dataChanged();
        else
            checked_changed();
    }
    else if(item == m_quantityItem)
        quantity_dataChanged();
}

void ItemRow::name_dataChanged()
{
    m_item->setName(m_nameItem->text());
}

void ItemRow::quantity_dataChanged()
{
    m_item->setQuantity(m_quantityItem->data(QuantityDelegate::dataRole()).toUInt());
}

void ItemRow::checked_changed()
{
    m_item->setIgnored(m_nameItem->checkState() == Qt::Unchecked);
}

void ItemRow::item_nameChanged(QString name)
{
    m_nameItem->setText(name);

    emit columnWidthChanged(m_nameItem->column());
}

void ItemRow::item_quantityChanged(uint quantity)
{
    m_quantityItem->setText(QuantityDelegate::textFromValue(quantity));
    m_quantityItem->setData(quantity, QuantityDelegate::dataRole());

    emit columnWidthChanged(m_quantityItem->column());
}

void ItemRow::item_ignoreStateChanged(bool ignored)
{
    Qt::CheckState state = ignored ? Qt::Unchecked : Qt::Checked;
    if(m_nameItem->checkState() != state)
        m_nameItem->setCheckState(state);
}

void ItemRow::clipboard_dataChanged()
{
    updateDummyRowStatus();
}

const bool ItemRow::validAndUnknownUrlInClipboard() const
{
    if(!m_item)
        return false;

    const QUrl url(urlFromClipboard());

    if(!isValidUrl(url))
        return false;

    foreach(SourceRow *sr, m_sourceRows)
        if(sr->source()->url() == url)
            return false;

    return true;
}

void ItemRow::updateDummyRowStatus()
{
    assert(m_dummyRow);

    if(validAndUnknownUrlInClipboard())
        m_dummyRow->setIcon(QIcon(":/source_url_add"));
    else
        m_dummyRow->setIcon(QIcon(":/source_user_add"));

    emit dummyStatusChanged();
}

void ItemRow::item_sourceAdded(Source *source)
{
    SourceRow *sr(new SourceRow(source, this));
    m_sourceRows.append(sr);

    // connect

    connect(sr, SIGNAL(columnWidthChanged(int))
        , this, SIGNAL(columnWidthChanged(int)));

    connect(sr, SIGNAL(multipleColumnWidthsChanged())
        , this, SIGNAL(multipleColumnWidthsChanged()));

    firstColumnItem()->insertRow(m_dummyRow->row(), sr->items());

    emit select(source);
    emit multipleColumnWidthsChanged();   

    updateDummyRowStatus();
}

void ItemRow::item_sourceRemoved(Source *source)
{
    SourceRow *sr(sourceRow(source));

    int index = m_sourceRows.indexOf(sr);
    m_sourceRows.remove(index);

    if(index > 0)
        --index;

    const int row = sr->row();
    firstColumnItem()->takeRow(row);

    delete sr;

    if(m_sourceRows.size() < 1)
        emit select(m_item);
    else
        emit select(m_sourceRows[index]->source());

    updateDummyRowStatus();
}

SourceRow *ItemRow::sourceRow(QStandardItem *item)
{
    foreach(SourceRow *sr, m_sourceRows)
        if(sr->hasItemInRow(item))
            return sr;

    return NULL;
}

SourceRow *ItemRow::sourceRow(Source *source)
{
    foreach(SourceRow *sr, m_sourceRows)
        if(sr->source() == source)
            return sr;

    return NULL;
}

const bool ItemRow::hasItemInDummyRow(QStandardItem *item) const
{
    assert(m_dummyRow);
    return m_dummyRow->hasItemInRow(item);
}
